#pragma once
#include"levels.hpp"
#include"util.hpp"
#include"message.hpp"
#include<vector>
#include<sstream>
#include<ctime>
#include<cassert>
#include<utility>
//进行日志格式化处理
//   time_t _time;//日志时间
//         loglevel::level _level;//日志等级,要指定类域
//         std::string _file;//文件名
//         size_t _line;//行号
//         std::string _logger;//日志器名称
//         std::string _payload;//日志消息主体
//         std::thread _tid;//线程id
//     };
namespace logs
{
    class Format
    {
    public:
        using ptr = std::shared_ptr<Format>;//取别名的意义?
        virtual void format(std::ostream& out,const logs::LogMsg& lsg) = 0;
    };
    class LevelFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<logs::loglevel::to_String(lsg._level);
        }
    };
    class TimeFormat:public Format
    {
    public:
        TimeFormat(const std::string& pattern)
        :_pattern(pattern)
        {
            ;
        }
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            struct tm st;
            localtime_r(&lsg._time, &st);//将时间戳转为tm结构体
            char arr[32] = {0};
            strftime(arr, sizeof(arr), _pattern.c_str(),&st);//将tm结构体内的时间按指定格式转到arr数组中
            out<<arr;
        }
    private:
        std::string _pattern;
    };
     class LinelFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<(lsg._line);
        }
    }; 
    class LoggerFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<lsg._logger;
        }
    };
     class PayloadFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<lsg._payload;
        }
    };
      class FileFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<lsg._file;
        }
    };
      class TidFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<lsg._tid;
        }
    };
     class NlineFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<"\n";
        }
    };
    class TableFormat:public Format
    {
    public:
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<"\t";
        }
    };
     class OtherFormat:public Format
    {
    public:
        OtherFormat(const std::string& val)
        :_val(val)
        {
            ;
        }
        std::string _val;
        void format(std::ostream& out,const logs::LogMsg& lsg)override
        {
            out<<_val;
        }
    };
    // %d 表示输出日期
    // %t 表示输出线程id
    // %c 表示输出日志器名称
    // %f 表示源码文件名
    // %l 表示行号
    // %p 表示日志等级
    // %T 表示缩进
    // %m 表示日志消息主体
    // %n 表示换行

    //格式化类
    class Formater
    {
    public:
        using ptr = std::shared_ptr<Formater>;
        Formater(const std::string& format = "[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
        :_format(format)
        {
            assert(parttern());//开始解析格式字符串
        }
        
        void format(std::ostream& out,const LogMsg& msg)
        {
            for(auto& e : _vf)
            {
                e->format(out,msg);
            }
        }
        std::string format(const LogMsg& msg)//返回日志消息
        {
            std::stringstream ss;
            format(ss,msg);
            return ss.str();
        }
    private:
        bool parttern()
        {
            std::vector<std::pair<std::string,std::string>> vss;
            std::string key,val;//这两个变量不能放在for内部
            for(int i = 0; i < _format.size();)
            {
                if(_format[i] != '%')//是普通字符
                {
                    val.push_back(_format[i++]);
                    continue;
                }
                //遇到%,如果是%%，此时我们认为是将%看成普通字符
                if(_format[i] == '%' && _format[i+1] == '%')//是普通字符
                {
                    val.push_back(_format[i]);
                    i+=2;
                    continue;
                }
                else//解析%
                {
                    if(val.size())//先push先前的普通字符到vss数组中
                        vss.push_back(std::make_pair(key,val));
                    val = "";//一定要清空val ab%d
                    if(i+1 == _format.size())//%
                    {
                        std::cout<<"%之后没有格式化字符"<<std::endl;
                        return false;
                    }
                    key = _format[++i];
                    i++;//跳过%d中的d，不然会被当成普通字符添加到日志消息中
                    //%d{%H},判断后面是否有格式子串,也有可能到结尾,我们认为{}是前面一个格式字符%的子串
                    if(i < _format.size() && _format[i] == '{')
                    {
                        int pos = _format.find_first_of("}",i);
                        if(pos == -1)
                        {
                            std::cout<<"无匹配的},输入错误"<<std::endl;
                            return false;
                        }
                        i = ++i;
                        val = _format.substr(i,pos-i);
                        i = pos+1;//跳过"%H:%S:%S"这个格式子串
                    } 
                    
                    vss.push_back(std::make_pair(key,val));
                    val = "";
                    key = "";
                }
            }
            vss.push_back(std::make_pair(key,val));//处理最后的原始字符
            //解析完后要开始创建格式化子类用来初始化_vf数组
            for(auto& e : vss)
            {
                _vf.push_back(CreateFormat(e.first,e.second));
            }
            return true;
        }
        
        //根据传入的格式字符,创建对应的类对象放到_vf中去,而格式字符是parttern()函数解析出来的
        Format::ptr CreateFormat(const std::string& key,const std::string& val)
        {
            if(key == "d") return std::make_shared<TimeFormat>(val);
            if(key == "t") return std::make_shared<TidFormat>();
            if(key == "c") return std::make_shared<LoggerFormat>();
            if(key == "f") return std::make_shared<FileFormat>();
            if(key == "l") return std::make_shared<LinelFormat>();
            if(key == "p") return std::make_shared<LevelFormat>();
            if(key == "m") return std::make_shared<PayloadFormat>();
            if(key == "n") return std::make_shared<NlineFormat>();
            if(key == "T") return std::make_shared<TableFormat>();
            if(key == "")  return std::make_shared<OtherFormat>(val);
            //例如遇到%g
            std::cout<<"%之后的格式字符输入错误:% "<<key<<std::endl;
            abort();
            return Format::ptr();//返回什么都行，都不会被调用
        }
    private:
        std::string _format;//日志格式
        std::vector<Format::ptr> _vf;//保存格式处理函数,后续按顺序调用
    };
};